<?php

namespace addons\yungift\model;

use addons\yungift\library\Logic;
use addons\yungift\library\ModelTrait;
use think\Db;
use think\Exception;
use think\Model;
use traits\model\SoftDelete;

/**
 * 礼币 - 账户
 */
class FundUser extends Model
{
    use ModelTrait;
    use SoftDelete;

    // 表名,不含前缀
    protected $name = 'yungift_fund_user';

    // 自动写入时间戳字段
    protected $autoWriteTimestamp = true;

    // 定义时间戳字段名
    protected $deleteTime = 'deleted_at';
    protected $updateTime = 'updated_at';
    protected $createTime = 'created_at';

    // 不显示的字段
    protected $hidden = ['deleted_at'];

    protected $resultSetType = 'collection';

    // 自定义初始化
    protected static function init()
    {
        FundUser::event('before_insert', function ($item) {
            // 对象默认值 - 必须使用当前类来初始化
            Logic::setDefaultValue($item, [
                'amount_give' => 0,
                'amount_left' => 0,
                'amount_use'  => 0,
                'amount_back' => 0
            ]);

            return true;
        });
    }

    // 活动数据
    public function activityData()
    {
        return $this->belongsTo(Activity::class, 'activity_id', 'id');
    }

    // 成员数据
    public function memberData()
    {
        return $this->belongsTo(Member::class, 'member_id', 'id');
    }

    // 状态
    const STATUS_NORMAL = 1;
    const STATUS_HIDDEN = 2;

    public static function getStatusList()
    {
        return [self::STATUS_NORMAL => __('正常'), self::STATUS_HIDDEN => __('屏蔽')];
    }

    public function getStatusTextAttr($value, $data)
    {
        $statusList = self::getStatusList();

        return $statusList[$data['status']] ?? $data['status'];
    }

    /**
     * 增减礼币
     *
     * @param $activityId
     * @param $memberId
     * @param $action
     * @param int $amount
     * @param string $sourceType
     * @param int $sourceId
     * @param string $fromType
     * @param int $fromId
     * @throws Exception
     * @throws \think\exception\DbException
     */
    public static function amountCounter(
        $activityId,
        $memberId,
        $action,
        $amount = 0,
        $sourceType = '',
        $sourceId = 0,
        $fromType = '',
        $fromId = 0,
        $fundUserId = 0
    ) {

        // 初始化账户
        if ($fundUserId) {
            $fundUser = FundUser::get($fundUserId);
        } else {
            $fundUser = FundUser::get(['activity_id' => $activityId, 'member_id' => $memberId]);
        }
        if (! $fundUser) {
            throw new Exception('礼币账户未开通');
        }
        // 数据加锁 - 余额才是最新值
        $fundUser = FundUser::where(['id' => $fundUser->id])->lock(true)->find();
        if (! in_array($action, [
            FundRecord::ACTION_SYSTEM_ROLLBACK,
            FundRecord::ACTION_BATCH_INIT,
            FundRecord::ACTION_BATCH_PLUS,
            FundRecord::ACTION_BATCH_MINUS,
            FundRecord::ACTION_MANUAL_PLUS,
            FundRecord::ACTION_MANUAL_MINUS
        ])) {
            if ($fundUser->status == FundUser::STATUS_HIDDEN) {
                throw new Exception('礼币账户被禁用');
            }
        }

        // 剩余校验
        if ($amount < 0 && ! in_array($action, [
                FundRecord::ACTION_SYSTEM_ROLLBACK,
                FundRecord::ACTION_BATCH_MINUS,
                FundRecord::ACTION_MANUAL_MINUS
            ])) {
            if ($fundUser->amount_left < abs($amount)) {
                throw new Exception('剩余礼币不够');
            }
        }

        // 礼币记录
        $fundRecord = new FundRecord();
        $fundRecord->fund_user_id = $fundUser->id;
        $fundRecord->activity_id = $fundUser->activity_id;
        $fundRecord->member_id = $fundUser->member_id;
        $fundRecord->action = $action;
        $fundRecord->source_type = $sourceType;
        $fundRecord->source_id = $sourceId;
        $fundRecord->from_type = $fromType;
        $fundRecord->from_id = $fromId;

        // 获取礼币
        if ($amount == 0) {
            if (! $amount = FundUser::getActionAmount($fundUser->id, $fundRecord->action,
                $fundRecord->source_type, $fundRecord->source_id, $fundRecord->from_type,
                $fundRecord->from_id)) {
                return false;
            }
        }
        $fundRecord->amount = $amount;
        $fundRecord->after_amount = $fundUser->amount_left + $amount;

        // 增减礼币
        Db::transaction(function () use ($fundRecord) {
            // 保存记录
            $fundRecord->save();

            // 处理账户
            $query = FundUser::where([
                'activity_id' => $fundRecord->activity_id,
                'member_id'   => $fundRecord->member_id
            ]);
            if ($fundRecord->amount > 0) {  // 正常获得
                $tAmount = $fundRecord->amount;
                if ($fundRecord->action == FundRecord::ACTION_GIFT_BACK) {  // 订单退回
                    $query->inc('amount_left', $tAmount)->inc('amount_back', $tAmount)->update();
                } else {
                    $query->inc('amount_left', $tAmount)->inc('amount_give', $tAmount)->update();
                }
            } else {
                $absAmount = abs($fundRecord->amount);
                if (in_array($fundRecord->action, [
                    FundRecord::ACTION_SYSTEM_ROLLBACK,
                    FundRecord::ACTION_BATCH_MINUS,
                    FundRecord::ACTION_MANUAL_MINUS
                ])) {  // 人工减少
                    $query->dec('amount_left', $absAmount)->dec('amount_give', $absAmount)->update();
                } else {  // 正常消费
                    $query->where('amount_left', '>=', $absAmount);
                    $row = $query->dec('amount_left', $absAmount)->inc('amount_use', $absAmount)->update();
                    if (! $row) {
                        throw new Exception('剩余礼币不够');
                    }
                }
            }
        });

        return true;
    }

    /**
     * 根据行为获取礼币
     *
     * @param $fundUserId
     * @param $action
     * @param $sourceType
     * @param $sourceId
     * @param $fromType
     * @param $fromId
     * @return int|mixed
     */
    public static function getActionAmount($fundUserId, $action, $sourceType, $sourceId, $fromType, $fromId)
    {
        $amount = 0;
        switch ($action) {
            case FundRecord::ACTION_FIRST_LOGIN:
                if (! FundRecord::where([
                    'fund_user_id' => $fundUserId,
                    'action'       => FundRecord::ACTION_FIRST_LOGIN,
                ])->exists()) {
                    $config = get_addon_instance('yungift');
                    $amount = $config['amount_first_login'] ?? 0;
                }
                break;
        }

        return $amount;
    }
}
